package com.cg.asm.core.config.mvc;

import com.cg.asm.core.config.loading.cache.auth.IAuthApi;
import com.cg.asm.core.domain.vo.auth.AuthApiJoinVO;
import com.cg.asm.core.domain.vo.auth.AuthRegVO;
import com.cg.asm.core.service.auth.IAuthApiService;
import com.cg.asm.client.DateUtil;
import com.cg.asm.client.IpAddrUtils;
import com.cg.asm.client.constans.ConstantsEnum;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * 访问控制拦截器
 */
@Log
public class ApiSecurityConfigurer implements HandlerInterceptor {

    @Autowired
    private IAuthApi authApi;
    @Autowired
    private IAuthApiService authApiService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) {
        final String authId = httpServletRequest.getParameter("authId");
        if (StringUtil.isNotEmpty(authId)) {
            boolean checkAuthRegResult = this.checkAuthReg(authId, httpServletRequest, httpServletResponse);
            if (checkAuthRegResult) {
                String requestUrl = httpServletRequest.getRequestURI();
                AuthApiJoinVO authApiJoinVO = authApi.getRequestAuthApi(authId, requestUrl);
                if (null != authApiJoinVO) {
                    //验证授权API接口
                    if (requestUrl.contains(authApiJoinVO.getApiInterface())) {
                        //验证访问次数
                        if (!this.checkRequestNumber(authApiJoinVO)) {
                            //request_number_exceeded:请求次数已超出最大请求次数
                            log.info(ConstantsEnum.API_REQUEST_NUMBER_EXCEEDED.getValue());
                            this.responseWriter(httpServletResponse, 401, ConstantsEnum.API_REQUEST_NUMBER_EXCEEDED.getKey());
                            return false;
                        }
                    } else {
                        //auth_interface_invalid:授权接口无效
                        log.info(ConstantsEnum.API_AUTH_INTERFACE_INVALID.getValue());
                        this.responseWriter(httpServletResponse, 401, ConstantsEnum.API_AUTH_INTERFACE_INVALID.getKey());
                        return false;
                    }
                } else {
                    //auth_invalid:授权码无效
                    log.info(ConstantsEnum.API_AUTH_INVALID.getValue());
                    this.responseWriter(httpServletResponse, 401, ConstantsEnum.API_AUTH_INVALID.getKey());
                    return false;
                }
            } else {
                return false;
            }
        } else {
            //auth_is_null:授权码为空
            log.info(ConstantsEnum.API_AUTH_IS_NULL.getValue());
            this.responseWriter(httpServletResponse, 401, ConstantsEnum.API_AUTH_IS_NULL.getKey());
            return false;
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
    }

    /**
     * 检查IP是否合法
     *
     * @param requestIP
     * @param authIp
     * @return
     */
    private boolean checkIP(String requestIP, String authIp) {
        boolean requestIpIsOk = true;//授权IP为空时，不验证IP，因此默认合法
        if (StringUtil.isNotEmpty(authIp)) {
            requestIpIsOk = false;//授权IP不为空时，初始为不合法，待验证时根据验证结果进行重置
            String[] apiAuthIPs = authIp.split(";");
            for (String apiAuthIP : apiAuthIPs) {
                if (requestIP.equals(apiAuthIP)) {
                    requestIpIsOk = true;//授权IP中存在请求IP，标示为合法，并跳出循环
                    break;
                }
            }
        }
        return requestIpIsOk;
    }

    /**
     * 验证授权注册信息
     *
     * @param authId
     * @param httpServletRequest
     * @param httpServletResponse
     * @return
     */
    private boolean checkAuthReg(String authId, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        AuthRegVO authRegVO = authApi.getAuthRegMap().get(authId);
        if (null != authRegVO) {
            //验证IP有效性
            String requestIP = IpAddrUtils.getIpAddr(httpServletRequest);
            if (!this.checkIP(requestIP, authRegVO.getAuthIp())) {
                //auth_ip_invalid:授权IP无效
                log.info(ConstantsEnum.API_AUTH_IP_INVALID.getValue());
                this.responseWriter(httpServletResponse, 401, ConstantsEnum.API_AUTH_IP_INVALID.getKey());
                return false;
            }
            return true;
        } else {
            //auth_invalid:授权码无效
            log.info(ConstantsEnum.API_AUTH_INVALID.getValue());
            this.responseWriter(httpServletResponse, 401, ConstantsEnum.API_AUTH_INVALID.getKey());
            return false;
        }
    }

    /**
     * 检查请求次数是否合法
     */
    private boolean checkRequestNumber(AuthApiJoinVO authApiJoinVO) {
        boolean requestNumberIsOk = true; //授权次数为空时，不验证请求次数，因此默认合法
        if (StringUtil.isNotEmpty(authApiJoinVO.getAuthApiMaxCount())) {
            String parsePatterns = "yyyy-MM-dd";
            String authApiRequestDate = "";
            if (null != authApiJoinVO.getAuthApiRequestDate()) {
                authApiRequestDate = DateUtil.format(authApiJoinVO.getAuthApiRequestDate(), parsePatterns);
            }
            if (DateUtil.getDate(parsePatterns).equals(authApiRequestDate) &&
                    StringUtil.isNotEmpty(authApiJoinVO.getAuthApiCurrentCount())) {
                Integer authApiCurrentCount = Integer.parseInt(authApiJoinVO.getAuthApiCurrentCount());
                Integer authApiMaxCount = Integer.parseInt(authApiJoinVO.getAuthApiMaxCount());
                if (authApiMaxCount > authApiCurrentCount) {
                    authApiJoinVO.setAuthApiCurrentCount(String.valueOf(authApiCurrentCount + 1));
                    authApiService.setRequestData(authApiJoinVO);
                } else {
                    requestNumberIsOk = false;//请求次数大于等于授权次数时，标示为不合法
                }
            } else {
                authApiJoinVO.setAuthApiRequestDate(new Date());
                authApiJoinVO.setAuthApiCurrentCount("1");
                authApiService.setRequestData(authApiJoinVO);
            }
        }
        return requestNumberIsOk;
    }


    /**
     * 返回请求结果
     *
     * @param httpResponse
     * @param status
     * @param resultValue
     */
    private void responseWriter(HttpServletResponse httpResponse, int status, String resultValue) {
        try {
            httpResponse.setStatus(status);
            httpResponse.getWriter().print(resultValue);
            httpResponse.getWriter().flush();
            httpResponse.getWriter().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
